﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;

namespace Common.Tools.Encrypt
{
    public enum MD5Length
    {
        /// <summary>
        /// 16
        /// </summary>
        Sixteen = 16,
        /// <summary>
        /// 32
        /// </summary>
        ThirtyTwo = 32
    }
    public class MD5
    {
        #region MD5
        /// <summary>
        /// MD5加密
        /// </summary>
        /// <param name="str">需加密字符串</param>
        /// <param name="length">16位或32位,32位采用.net默认MD5加密算法</param>
        /// <returns>加密后的字符串</returns>
        public static string Encrypt(string str, MD5Length length = MD5Length.ThirtyTwo)
        {
            if (string.IsNullOrEmpty(str))
                return string.Empty;
            MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider();
            byte[] encryptedBytes = md5.ComputeHash(Encoding.ASCII.GetBytes(str));
            StringBuilder sb = new StringBuilder();
            switch (length)
            {
                case MD5Length.Sixteen://16位密文是32位密文的9到24位字符
                    for (int i = 4; i < 12; i++)
                        sb.AppendFormat("{0:x2}", encryptedBytes[i]);
                    break;
                default:
                    for (int i = 0; i < encryptedBytes.Length; i++)
                        sb.AppendFormat("{0:x2}", encryptedBytes[i]);
                    break;
            }
            return sb.ToString();
        }
        public static string Encrypt(System.IO.Stream stream, MD5Length length = MD5Length.ThirtyTwo)
        {
            if (stream == null || stream.Length == 0)
                return string.Empty;
            MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider();
            byte[] encryptedBytes = md5.ComputeHash(stream);
            StringBuilder sb = new StringBuilder();
            switch (length)
            {
                case MD5Length.Sixteen://16位密文是32位密文的9到24位字符
                    for (int i = 4; i < 12; i++)
                        sb.AppendFormat("{0:x2}", encryptedBytes[i]);
                    break;
                default:
                    for (int i = 0; i < encryptedBytes.Length; i++)
                        sb.AppendFormat("{0:x2}", encryptedBytes[i]);
                    break;
            }
            return sb.ToString();
        }
        /// <summary>
        /// 文件流MD5加密简化加速版
        /// </summary>
        /// <param name="stream"></param>
        /// <param name="encryptLength">加密字节长度（大于该字节时取首尾部分的该长度的字节和文件流总长度进行加密）（必须大于0）</param>
        /// <param name="length"></param>
        /// <returns></returns>
        public static string EncryptSimple(System.IO.Stream stream, int encryptLength = 131072, MD5Length length = MD5Length.ThirtyTwo)
        {
            if (stream == null || stream.Length == 0)
                return string.Empty;
            if (encryptLength < 1)
                return string.Empty;
            MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider();
            byte[] encryptedBytes = md5.ComputeHash(GetSimpleBytes(stream, encryptLength));
            StringBuilder sb = new StringBuilder();
            switch (length)
            {
                case MD5Length.Sixteen://16位密文是32位密文的9到24位字符
                    for (int i = 4; i < 12; i++)
                        sb.AppendFormat("{0:x2}", encryptedBytes[i]);
                    break;
                default:
                    for (int i = 0; i < encryptedBytes.Length; i++)
                        sb.AppendFormat("{0:x2}", encryptedBytes[i]);
                    break;
            }
            return sb.ToString();
        }
        private static byte[] GetSimpleBytes(System.IO.Stream stream, int encryptLength)
        {
            byte[] array = new byte[encryptLength];
            int num = stream.Read(array, 0, encryptLength);
            if (num < encryptLength)
            {
                return array;
            }

            stream.Position = stream.Length - encryptLength;
            byte[] arrayLength = Encoding.Default.GetBytes(stream.Length.ToString());
            byte[] arrayNew = new byte[encryptLength * 2 + arrayLength.Length];
            Array.Copy(array, 0, arrayNew, 0, encryptLength);
            stream.Read(arrayNew, encryptLength, encryptLength);
            Array.Copy(arrayLength, 0, arrayNew, encryptLength * 2, arrayLength.Length);
            return arrayNew;
        }
        ///// <summary>
        ///// MD5加密,和动网上的16/32位MD5加密结果相同
        ///// </summary>
        ///// <param name="strSource">待加密字符串</param>
        ///// <param name="length">16或32值之一,其它则采用.net默认MD5加密算法</param>
        ///// <returns>加密后的字符串</returns>
        //public static string MD5EncryptB(string source, MD5Length length = MD5Length.ThirtyTwo)//默认参数
        //{
        //    if (string.IsNullOrEmpty(source))
        //        return string.Empty;
        //    HashAlgorithm provider = CryptoConfig.CreateFromName("MD5") as HashAlgorithm;

        //    byte[] hashValue = provider.ComputeHash(Encoding.ASCII.GetBytes(source));
        //    StringBuilder sb = new StringBuilder();
        //    switch (length)
        //    {
        //        case MD5Length.Sixteen://16位密文是32位密文的9到24位字符
        //            for (int i = 4; i < 12; i++)
        //                sb.Append(hashValue[i].ToString("x2"));
        //            break;
        //        case MD5Length.ThirtyTwo:
        //            for (int i = 0; i < 16; i++)
        //            {
        //                sb.Append(hashValue[i].ToString("x2"));
        //            }
        //            break;
        //        default:
        //            for (int i = 0; i < hashValue.Length; i++)
        //            {
        //                sb.Append(hashValue[i].ToString("x2"));
        //            }
        //            break;
        //    }
        //    return sb.ToString();
        //}
        #endregion MD5
    }
}
